package ca.tatham.triplipse.filter;

import org.openrdf.model.Value;

import ca.tatham.triplipse.PrefixProvider;
import ca.tatham.triplipse.RdfStatement;

/**
 * A basic filter that allows filtering on any or all of the RDF fields of a
 * triple, either through inclusion or exclusion.
 * 
 * @author BenTatham
 */
public class RdfStatementFilterPart implements IRdfStatementFilter {

	public enum FilterType {
		INCLUDE, EXCLUDE
	}

	public enum FilterField {
		ANY, ALL, SUBJECT, PREDICATE, OBJECT
	}

	private String m_filter;
	private FilterType m_type;
	private FilterField m_field;

	public RdfStatementFilterPart(String filter, FilterType type,
			FilterField field) {
		m_filter = filter;
		m_type = type;
		m_field = field;
	}

	public String getFilter() {
		return m_filter;
	}

	public FilterType getType() {
		return m_type;
	}

	public FilterField getField() {
		return m_field;
	}

	public boolean includeStatement(RdfStatement rdfStatement) {
		return includeStatement(rdfStatement, null);
	}

	public boolean includeStatement(RdfStatement rdfStatement,
			PrefixProvider provider) {
		switch (m_type) {
		case INCLUDE:
			return handleInclude(rdfStatement, provider);
		case EXCLUDE:
			return !handleInclude(rdfStatement, provider);
		}
		return false;
	}

	private boolean handleInclude(RdfStatement rdfStatement,
			PrefixProvider provider) {
		switch (m_field) {
		case ANY:
			return doesMatch(rdfStatement.getSubject(), provider)
					|| doesMatch(rdfStatement.getPredicate(), provider)
					|| doesMatch(rdfStatement.getObject(), provider);
		case ALL:
			return doesMatch(rdfStatement.getSubject(), provider)
					&& doesMatch(rdfStatement.getPredicate(), provider)
					&& doesMatch(rdfStatement.getObject(), provider);
		case SUBJECT:
			return doesMatch(rdfStatement.getSubject(), provider);
		case PREDICATE:
			return doesMatch(rdfStatement.getPredicate(), provider);
		case OBJECT:
			return doesMatch(rdfStatement.getObject(), provider);
		}
		return false;
	}

	private boolean doesMatch(Value value, PrefixProvider provider) {
		String string = value.toString();
		if (provider == null) {
			return doesMatch(string);
		}
		if (doesMatch(string)) {
			return true;
		}
		String[] prefix = provider.getPrefix(string);
		if (prefix == null) {
			return false;
		}
		string = prefix[0] + ':' + string.substring(prefix[1].length());
		return doesMatch(string);
	}

	private boolean doesMatch(String value) {
		return value.indexOf(m_filter) > -1;
	}

}
